//机器人
const User=require('./User');
const Events=require('events')
class Bot extends User{
    constructor(options,docker){
        super(options,docker);
        this.isBot=true; //是否是机器人的标识
        this.IQ=Math.random()*0.3+0.1; //机器人智商，智商越低，停顿时间越长
        this.character=0;  //性格  0为喜欢杀玩家   1为喜欢杀机器人  2喜欢炸箱子  3喜欢乱走乱放泡泡
        this.usedBombCount=0; //该局中使用过的泡泡
        this.events=new Events();
        this.events.on('gameStart',this.onGameStart.bind(this));
        this.events.on('gameReady',this.onGameReady.bind(this));
        this.events.on('gameOver',this.onGameOver.bind(this));
        this.events.on('changeUserStatus',this.onChangeUserStatus.bind(this));
    }
    sendEvent(eventName,data){
        // console.log('机器人收到事件:',eventName,data);
        this.events.emit(eventName,data);
    }
    onGameStart(){
        //模拟发送加载进度;
        setTimeout(()=>{
            if(!!this.room)
                this.room.broadcastEvent('loadProcess',{i:this.index,process:Math.floor(Math.random()*20)});
        },500);
        setTimeout(()=>{
            if(!!this.room)
                this.room.broadcastEvent('loadProcess',{i:this.index,process:Math.floor(Math.random()*20)+20});
        },1000);
        setTimeout(()=>{
            if(!!this.room)
                this.room.broadcastEvent('loadProcess',{i:this.index,process:Math.floor(Math.random()*20)+40});
        },1500);
        setTimeout(()=>{
            if(!!this.room)
                this.room.broadcastEvent('loadProcess',{i:this.index,process:Math.floor(Math.random()*20+60)});
        },2000);
        setTimeout(()=>{
            if(!!this.room)
                this.room.broadcastEvent('loadProcess',{i:this.index,process:Math.floor(Math.random()*20+80)});
        },2500);
        setTimeout(()=>{
            if(!!this.room)
                this.room.broadcastEvent('loadProcess',{i:this.index,process:100});
        },3000);
        //发送准备
        setTimeout(()=>{
            this.ready();
        },3500);
    }
    onGameReady(){
        this._runTimer=setTimeout(()=>{
            if(!!this.room){
                this.room.queue.pushTry(function(){
                    this._run();
                }.bind(this));
            }
        },2000+Math.floor(Math.random()*2000));
    }
    onGameOver(){
        this._end();
    }
    onChangeUserStatus(data={index:0,status:0}){
        //如果有人死亡，则设定第一个机器人为喜欢杀玩家，第二个机器人喜欢杀机器人
        if(data.status===-1){
            console.log('有人死亡，重新设定机器人性格！');
            let bots=this.room.users.filter(item=>{return !!item.isBot && item.status != -1;});
            if(bots.length>0){
                bots[0].character=0;
            }
            if(bots.length>1){
                bots[1].character=1;
            }
            if(bots.length>2){
                bots[2].character=2;
            }
            if(bots.length>3){
                bots[3].character=3;
            }
        }
    }
    //机器人开始运行
    _run(){
        if(this.status===0){
            //获取可以去到的点位
            let posArray=[{x:this.x,y:this.y,range:0}];
            this._computeCanPosArray([{x:this.x,y:this.y}],posArray);
            //获取预爆炸点
            let bombArray=[];
            let now=new Date().getTime();
            //即将爆炸的泡泡
            let beBombBombs=this.room.bombs;//.filter(item=>{return now-item.createTimeTick>3000});
            let leftBombs=[];//this.room.bombs.filter(item=>{return now-item.createTimeTick<=3000});
            this._computeBombArray(beBombBombs,leftBombs,bombArray);
            // console.log('bombArray:',bombArray);
            //计算可以去到的点位的权重值，并附加到数组元素中
            this._computeCanPosPower(posArray,bombArray);
            //根据算出的点位权重再次排序,权重相同按照远近进行排序
            posArray.sort((a,b)=>{return b.power-a.power;});//b.power!==a.power?b.power-a.power:a.range-b.range;});
            //拿到最高权重的目标位置
            let pos=posArray[0];

            //前往该点位
            if(!!pos){
                if(!pos.startPos){
                    this.moveStop();
                    if(this.bombCount>0&&!bombArray.find(item=>{return item.x===this.x&&item.y===this.y;})){
                        this.usedBombCount++;
                        this.createBomb();
                    }
                }else{
                    let isDanger=false;
                    //智商大于0.7，且随机一般几率触发紧急避险
                    if(this.IQ > 0.2 && (this.IQ + 0.2) > Math.random()){
                        //紧急避险
                        //获取即将爆炸的点位
                        let beBombArray=[];
                        let delayTime=this.moveInterval*2;
                        let beBombBombs=this.room.bombs.filter(item=>{return now-item.createTimeTick>3000-delayTime});
                        let leftBombs=this.room.bombs.filter(item=>{return now-item.createTimeTick<=3000-delayTime});
                        this._computeBombArray(beBombBombs,leftBombs,beBombArray);
                        if(beBombArray.find(item=>{return item.x===pos.startPos.x&&item.y===pos.startPos.y})){
                            let toCheckPos=posArray.filter(item=>{return item.range===1&&!(item.x===pos.startPos.x&&item.x===pos.startPos.y)});
                            for(let i=0;i<toCheckPos.length;i++){
                                if(!beBombArray.find(item=>{return item.x===toCheckPos[i].x&&item.y===toCheckPos[i].y})){
                                    isDanger=true;
                                    pos.startPos={x:toCheckPos[i].x,y:toCheckPos[i].y};
                                    break;
                                }
                            }
                        }
                    }
                    //非紧急避险状态下，旁边如果有地方玩家，则放泡泡
                    if(!isDanger&&this.bombCount>0){
                        let nearPos=posArray.filter(item=>{return item.range<=2;});
                        let hasUser=false;
                        for(let i=0;i<nearPos.length;i++){
                            if(this.room.users.find(item=>{return item._id!==this._id&&item.status===0&&item.group!==this.group&&item.x===nearPos[i].x&&item.y===nearPos[i].y})){
                                hasUser=true;
                                break;
                            }
                        }
                        if(hasUser){
                            this.usedBombCount++;
                            this.createBomb();
                        }
                    }
                    //如果当前点不是爆炸点，则随机概率不动
                    let randomNumber=Math.random();
                    if(randomNumber>(0.3 + this.IQ)){
                        if(bombArray.find(item=>{return item.x===this.x&&item.y===this.y;})){
                            this.setPos(pos.startPos);
                        }else{
                            this.moveStop();
                        }
                    }else{
                        this.setPos(pos.startPos);
                    }
                }
            }
        }
        //判断是否需要用针救自己
        if(this.status===10&&this.thumbtackCount>0){
            let time=1000+Math.floor(Math.random()*1000);
            this._runTimer=setTimeout(()=>{
                if(!!this.room){
                    this.room.queue.pushTry(function(){
                        this.useThumbtack();
                        this._runTimer=setTimeout(()=>{
                            if(!!this.room){
                                this.room.queue.pushTry(function(){
                                    this._run();
                                }.bind(this));
                            }
                        },300);
                    }.bind(this));
                }
            },time);
        }else{
            let interval=this.moveInterval;
            let random=Math.random();
            if(random>this.IQ){
                interval+= 100 * (1-this.IQ) + Math.floor( Math.random()*(500 - interval));
            }
            this._runTimer=setTimeout(()=>{
                if(!!this.room){
                    this.room.queue.pushTry(function(){
                        this._run();
                    }.bind(this));
                }
            },interval);
        }

    }
    //计算自己可以移动到的坐标点,将坐标点填充到posArray
    //计算过程中startPos格式为{x:0,y:0};
    _computeCanPosArray(checkPosArray=[],posArray=[],range=1){
        let nextCheckPosArray=[]; //下一轮需要检测的点数组
        for(let i=0;i<checkPosArray.length;i++){
            let x=checkPosArray[i].x;
            let y=checkPosArray[i].y;
            let startPos=checkPosArray[i].startPos;
            let _x=x;
            let _y=y+1;
            if(this._checkMovePos(_x,_y)){
                let pos=posArray.find(item=>{return item.x===_x&&item.y===_y});
                if(!pos){
                    let pos={x:_x,y:_y,range:range};
                    if(!startPos){
                        pos.startPos={x:_x,y:_y};
                    }else{
                        pos.startPos=startPos;
                    }
                    posArray.push(pos);
                    nextCheckPosArray.push(pos);
                }
            }
            _x=x;
            _y=y-1;
            if(this._checkMovePos(_x,_y)){
                let pos=posArray.find(item=>{return item.x===_x&&item.y===_y});
                if(!pos){
                    let pos={x:_x,y:_y,range:range};
                    if(!startPos){
                        pos.startPos={x:_x,y:_y};
                    }else{
                        pos.startPos=startPos;
                    }
                    posArray.push(pos);
                    nextCheckPosArray.push(pos);
                }
            }
            _x=x+1;
            _y=y;
            if(this._checkMovePos(_x,_y)){
                let pos=posArray.find(item=>{return item.x===_x&&item.y===_y});
                if(!pos){
                    let pos={x:_x,y:_y,range:range};
                    if(!startPos){
                        pos.startPos={x:_x,y:_y};
                    }else{
                        pos.startPos=startPos;
                    }
                    posArray.push(pos);
                    nextCheckPosArray.push(pos);
                }
            }
            _x=x-1;
            _y=y;
            if(this._checkMovePos(_x,_y)){
                let pos=posArray.find(item=>{return item.x===_x&&item.y===_y});
                if(!pos){
                    let pos={x:_x,y:_y,range:range};
                    if(!startPos){
                        pos.startPos={x:_x,y:_y};
                    }else{
                        pos.startPos=startPos;
                    }
                    posArray.push(pos);
                    nextCheckPosArray.push(pos);
                }
            }
        }
        if(nextCheckPosArray.length>0){
            range++;
            this._computeCanPosArray(nextCheckPosArray,posArray,range);
        }

    }
    //判断单个点能否移动
    _checkMovePos(x,y){
        if(this.x===x&&this.y===y){
            return true;
        }
        if(!!this.room.map.boxes[y][x]||!!this.room.map.obstacles[y][x]){
            return false;
        }
        //如果该坐标有泡泡，不能去
        if(!!this.room.bombs.find(item=>{return item.x===x&&item.y===y})){
            return false;
        }
        return true;
    }
    //计算当前地图内所有炸弹将要爆炸的坐标点
    _computeBombArray(beBombBombs=[],leftBombs=[],bombArray=[]){
        for(let i=0;i<beBombBombs.length;i++){
            let x=beBombBombs[i].x;
            let y=beBombBombs[i].y;
            let power=beBombBombs[i].power;
            if(!bombArray.find(item=>{return item.x===x&&item.y===y})){
                bombArray.push({x:x,y:y});
            }
            for(let j=1;j<=power;j++){
                let pos={x:x+j,y:y};
                if(this._checkBoxAndObstacles(pos.x,pos.y)){
                    break;
                }else if(!bombArray.find(item=>{return item.x===pos.x&&item.y===pos.y})){
                    bombArray.push(pos);
                }
            }
            for(let j=1;j<=power;j++){
                let pos={x:x-j,y:y};
                if(this._checkBoxAndObstacles(pos.x,pos.y)){
                    break;
                }else if(!bombArray.find(item=>{return item.x===pos.x&&item.y===pos.y})){
                    bombArray.push(pos);
                }
            }
            for(let j=1;j<=power;j++){
                let pos={x:x,y:y+j};
                if(this._checkBoxAndObstacles(pos.x,pos.y)){
                    break;
                }else if(!bombArray.find(item=>{return item.x===pos.x&&item.y===pos.y})){
                    bombArray.push(pos);
                }
            }
            for(let j=1;j<=power;j++){
                let pos={x:x,y:y-j};
                if(this._checkBoxAndObstacles(pos.x,pos.y)){
                    break;
                }else if(!bombArray.find(item=>{return item.x===pos.x&&item.y===pos.y})){
                    bombArray.push(pos);
                }
            }
        }
        //判断剩余的泡泡是否有在当前爆炸点内的，如果有，则计算引爆点
        let nextBeBombBombs=leftBombs.filter(item=>{return !!bombArray.find(bomb=>{return item.x===bomb.x&&item.y===bomb.y})});
        if(nextBeBombBombs.length>0){
            let nextLeftBombs=leftBombs.filter(item=>{return !bombArray.find(bomb=>{return item.x===bomb.x&&item.y===bomb.y})});
            this._computeBombArray(nextBeBombBombs,nextLeftBombs,bombArray);
        }
    }
    //检测该点是否有箱子和障碍物，如果有，则爆炸波到此结束
    _checkBoxAndObstacles(x,y){
        return !!this.room.map.boxes[y][x]||!!this.room.map.obstacles[y][x];
    }
    //计算可以去的点的权重
    _computeCanPosPower(posArray=[],bombArray=[]){
        for(let i=0;i<posArray.length;i++){
            let power=0;
            let x=posArray[i].x;
            let y=posArray[i].y;
            //如果该点位四周有箱子，则根据箱子个数加权重
            let boxCount=this._getBoxCount(x,y);
            //判断四周能移动的点位有几个，2个以上每一个减权重10
            let emptyCount=this._getEmptyCount(x,y);


            //如果该点已经放了有泡泡，则减去权重
            let isPaoPao=!!this.room.bombs.find(item=>{return item.x===x&&item.y===y})

            //如果该点位是预爆炸点，则减去权重
            let isBeBomb=!!bombArray.find(item=>{return item.x===x&&item.y===y})

            //如果该点位有道具，则增加权重
            let isProperty=posArray[i].range<=6&&this.room.properties.find(item=>{return item.x===x&&item.y===y;});

            //如果附近有被泡住的玩家，则权重很高
            let isBombedUser=posArray[i].range<=10&&this.room.users.find(item=>{return item.status===10&&item.x===x&&item.y===y});

            //这个点是否有玩家
            let isNearUser=!!this.room.users.find(item=>{return item.status===0&&!item.isBot&&item.group!==this.group&&item._id!==this._id&&item.x===x&&item.y===y;});

            //这个点是否有机器人
            let isNearBot=!!this.room.users.find(item=>{return item.status===0&&!!item.isBot&&item.group!==this.group&&item._id!==this._id&&item.x===x&&item.y===y;});

            //游戏内是否还剩余有玩家
            let hasUser=!!this.room.users.find(item=>{return !item.isBot&&item.group!==this.group&&item.status===0});

            switch(this.character){
                case 0:{
                    power+=boxCount*5;
                    power-=posArray[i].range*2;
                    if(this.bombCount!==1||Math.random()>0.5){
                        power-=(emptyCount-1)*5;
                    }
                    if(isPaoPao){
                        power-=100;
                    }
                    if(isBeBomb){
                        power-=290;
                    }
                    if(isProperty&&(this.bombCount<4||this.power<4)){
                        let property=this.room.properties.find(item =>{return item.x===x&&item.y===y});
                        if(property.type!==2||this.moveInterval>200){
                            power+=50;
                        }
                    }
                    if(isBombedUser){
                        power+=500;
                    }
                    if(isNearUser){
                        power+=300;
                    }
                    break;
                }
                case 1:{
                    power+=boxCount*5;
                    power-=posArray[i].range*2;
                    if(this.bombCount!==1||Math.random()>0.5){
                        power-=(emptyCount-1)*5;
                    }
                    if(isPaoPao){
                        power-=100;
                    }
                    if(isBeBomb){
                        power-=290;
                    }
                    if(isProperty&&(this.bombCount<4||this.power<4)){
                        let property=this.room.properties.find(item =>{return item.x===x&&item.y===y});
                        if(property.type!==2||this.moveInterval>200){
                            power+=50;
                        }
                    }
                    if(isBombedUser){
                        power+=50;
                    }
                    if(isNearBot){
                        power+=300;
                    }
                    break;
                }
                case 2:{
                    power+=boxCount*50;
                    power-=posArray[i].range*20;
                    if(this.bombCount!==1||Math.random()>0.5){
                        power-=(emptyCount-1)*50;
                    }
                    if(isPaoPao){
                        power-=100;
                    }
                    if(isBeBomb){
                        power-=300;
                    }
                    if(isProperty){
                        let property=this.room.properties.find(item =>{return item.x===x&&item.y===y});
                        if(property.type!==2||this.moveInterval>200){
                            power+=50;
                        }
                    }
                    if(isBombedUser){
                        power+=500;
                    }
                    // if(isNearUser){
                    //     power+=300;
                    // }
                    break;
                }
                case 3:{
                    if(boxCount<3){
                        power+=boxCount*5;
                    }
                    power-=posArray[i].range*2;
                    if(this.bombCount!==1||Math.random()>0.5){
                        power-=(emptyCount-1)*5;
                    }
                    if(isPaoPao){
                        power-=100;
                    }
                    if(isBeBomb){
                        power-=300;
                    }
                    if(isProperty){
                        let property=this.room.properties.find(item =>{return item.x===x&&item.y===y});
                        if(property.type!==2||this.moveInterval>200){
                            power+=10;
                        }
                    }
                    if(isBombedUser){
                        power+=500;
                    }
                    // if(isNearUser){
                    //     power+=300;
                    // }
                    break;
                }
            }
            //如果放过的泡泡大于20个，并且地图只剩下一个机器人，那么这个机器人唯一的用途就是杀人
            // if(this.usedBombCount>20&&!this.room.users.find(item=>{return item.isBot&&item.status===0&&item._id!==this._id})&&this.room.users.find(item=>{return item.status===0&&!item.isBot&&item._id!==this._id&&item.x===x&&item.y===y;})){
            //     power+=500;
            // }
            // //如果地图中只剩下机器人，则第一个没死的机器人首先被其他人集火杀
            // if(this.usedBombCount>20&&!hasUser&&isNearBot){
            //     let bot=this.room.users.find(item=>{return item.isBot&&item.group!==this.group&&item.status===0})
            //     if(!!bot&&bot.x===this.x&&bot.y===this.y){
            //         power+=1000;
            //     }
            // }
            posArray[i].power=power;

        }
        // console.log('posArray:',posArray);
    }
    //获取四周箱子的个数
    _getBoxCount(x,y){
        let boxCount=0; //计算此地放个炸弹能炸到的箱子个数
        for(let i=1;i<=this.power;i++){
            if(!!this.room.map.obstacles[y][x-i]){
                break;
            }
            if(!!this.room.map.boxes[y][x-i]){
                boxCount++;
                break;
            }
        }
        for(let i=1;i<=this.power;i++){
            if(!!this.room.map.obstacles[y][x+i]){
                break;
            }
            if(!!this.room.map.boxes[y][x+i]){
                boxCount++;
                break;
            }
        }
        for(let i=1;i<=this.power;i++){
            if(!!this.room.map.obstacles[y-i][x]){
                break;
            }
            if(!!this.room.map.boxes[y-i][x]){
                boxCount++;
                break;
            }
        }
        for(let i=1;i<=this.power;i++){
            if(!!this.room.map.obstacles[y+i][x]){
                break;
            }
            if(!!this.room.map.boxes[y+i][x]){
                boxCount++;
                break;
            }
        }
        return boxCount;
    }
    //获取四周空位置的数量
    _getEmptyCount(x,y){
        let emptyCount=0; //计算四周的箱子个数
        if(this._checkMovePos(x-1,y)){
            emptyCount++;
        }
        if(this._checkMovePos(x+1,y)){
            emptyCount++;
        }
        if(this._checkMovePos(x,y-1)){
            emptyCount++;
        }
        if(this._checkMovePos(x,y+1)){
            emptyCount++;
        }
        return emptyCount;
    }
    //机器人结束运行
    _end(){
        this.usedBombCount=0;
        if(!!this._runTimer){
            clearTimeout(this._runTimer);
            this._runTimer=null;
        }
    }

    //重写的方法
    async hasDiamond(){
        return true;
    }
    async checkDiamond(num){
        return true;
    }

    async gameStartReduce(){
        this.thumbtackCount= Math.random() > 0.3 ? 1 : 0;
    }
}

module.exports=Bot;